"""
会话检测模块 (Session Detector)

基于时间间隔检测用户行为会话。
原理：相邻两个事件间隔超过阈值（默认5分钟），则认为是新会话。
"""

from datetime import datetime
from typing import List, Dict, Any
from collections import Counter


class SessionDetector:
    """会话检测器"""

    DEFAULT_GAP_MS = 5 * 60 * 1000  # 5分钟 = 300,000 毫秒

    def __init__(self, gap_threshold_ms: int = None):
        """
        初始化会话检测器

        Args:
            gap_threshold_ms: 会话间隔阈值（毫秒），默认 5 分钟
        """
        self.gap_threshold_ms = gap_threshold_ms or self.DEFAULT_GAP_MS

    def detect_sessions(self, events: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        检测事件流中的会话

        Args:
            events: 事件列表，每个事件必须包含 'timestamp' 字段

        Returns:
            会话列表，每个会话包含：
            - session_id: 会话ID（从1开始）
            - start_time: 开始时间（毫秒时间戳）
            - end_time: 结束时间（毫秒时间戳）
            - duration_sec: 持续时间（秒）
            - event_count: 事件数量
            - events: 事件列表
            - urls: 访问的URL列表（去重）
            - event_types: 事件类型统计
        """
        if not events:
            return []

        # 按时间戳排序
        sorted_events = sorted(events, key=lambda e: e.get('timestamp', 0))

        sessions = []
        current_session_events = []
        prev_timestamp = None
        session_id = 1

        for event in sorted_events:
            timestamp = event.get('timestamp', 0)

            # 检测会话间隔
            if prev_timestamp and (timestamp - prev_timestamp) > self.gap_threshold_ms:
                # 保存当前会话
                if current_session_events:
                    sessions.append(self._build_session(session_id, current_session_events))
                    session_id += 1

                # 开始新会话
                current_session_events = [event]
            else:
                # 继续当前会话
                current_session_events.append(event)

            prev_timestamp = timestamp

        # 保存最后一个会话
        if current_session_events:
            sessions.append(self._build_session(session_id, current_session_events))

        return sessions

    def _build_session(self, session_id: int, events: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        构建会话信息

        Args:
            session_id: 会话ID
            events: 会话内的事件列表

        Returns:
            会话信息字典
        """
        if not events:
            return {}

        start_time = events[0].get('timestamp', 0)
        end_time = events[-1].get('timestamp', 0)
        duration_ms = end_time - start_time

        # 统计事件类型
        event_types = Counter(e.get('eventType', 'unknown') for e in events)

        # 提取访问的URL（去重，保持顺序）
        urls = []
        seen_urls = set()
        for event in events:
            url = event.get('url', '')
            if url and url not in seen_urls:
                urls.append(url)
                seen_urls.add(url)

        return {
            'session_id': session_id,
            'start_time': start_time,
            'end_time': end_time,
            'duration_sec': round(duration_ms / 1000, 1),
            'event_count': len(events),
            'events': events,
            'urls': urls,
            'event_types': dict(event_types),
            'start_time_str': self._format_timestamp(start_time),
            'end_time_str': self._format_timestamp(end_time),
        }

    def _format_timestamp(self, timestamp_ms: int) -> str:
        """
        格式化时间戳

        Args:
            timestamp_ms: 毫秒时间戳

        Returns:
            格式化的时间字符串 (YYYY-MM-DD HH:MM:SS)
        """
        if not timestamp_ms:
            return 'N/A'

        try:
            dt = datetime.fromtimestamp(timestamp_ms / 1000)
            return dt.strftime('%Y-%m-%d %H:%M:%S')
        except Exception:
            return 'Invalid'

    def get_url_statistics(self, sessions: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        统计每个URL的访问情况

        Args:
            sessions: 会话列表

        Returns:
            URL统计列表，每个包含：
            - url: URL地址
            - visit_count: 访问次数（跨会话）
            - event_count: 事件数量
            - total_duration_sec: 总停留时间（秒）
            - avg_duration_sec: 平均停留时间（秒）
            - titles: 页面标题列表（去重）
        """
        url_stats = {}

        for session in sessions:
            for event in session['events']:
                url = event.get('url', '')
                if not url:
                    continue

                if url not in url_stats:
                    url_stats[url] = {
                        'url': url,
                        'visit_count': 0,
                        'event_count': 0,
                        'total_duration_ms': 0,
                        'titles': set(),
                        'visit_sessions': []
                    }

                url_stats[url]['event_count'] += 1

                # 记录标题
                title = event.get('title', '')
                if title:
                    url_stats[url]['titles'].add(title)

        # 计算每个URL在每个会话中的停留时间
        for session in sessions:
            url_events = {}
            for event in session['events']:
                url = event.get('url', '')
                if not url:
                    continue

                if url not in url_events:
                    url_events[url] = []
                url_events[url].append(event)

            # 计算每个URL在该会话的停留时间
            for url, events in url_events.items():
                if len(events) < 2:
                    continue

                first_ts = events[0].get('timestamp', 0)
                last_ts = events[-1].get('timestamp', 0)
                duration_ms = last_ts - first_ts

                url_stats[url]['total_duration_ms'] += duration_ms
                url_stats[url]['visit_count'] += 1
                url_stats[url]['visit_sessions'].append({
                    'session_id': session['session_id'],
                    'duration_sec': round(duration_ms / 1000, 1)
                })

        # 转换为列表并计算平均值
        result = []
        for stats in url_stats.values():
            total_duration_sec = round(stats['total_duration_ms'] / 1000, 1)
            avg_duration_sec = round(total_duration_sec / stats['visit_count'], 1) if stats['visit_count'] > 0 else 0

            result.append({
                'url': stats['url'],
                'visit_count': stats['visit_count'],
                'event_count': stats['event_count'],
                'total_duration_sec': total_duration_sec,
                'avg_duration_sec': avg_duration_sec,
                'titles': list(stats['titles']),
                'visit_sessions': stats['visit_sessions']
            })

        # 按事件数量降序排序
        result.sort(key=lambda x: x['event_count'], reverse=True)

        return result
